home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000
/
Ham Radio 2000.iso
/
ham2000
/
satellit
/
pfh0210
/
pfh.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-02-03
|
24KB
|
1,107 lines
/* several utility functions involving the Pacsat File Header */
/* copyright 1991 by PE1CHL */
#include <stdio.h>
#include <time.h>
#if defined(__TURBOC__) || defined(MSDOS)
#include <stdlib.h>
#include <string.h>
#else
extern char *strstr();
#endif
/* definition of a PFH item (used for verbose printout of PFH and user input) */
struct pfh
{
unsigned int id; /* PFH ID */
unsigned char type; /* printout type */
#define TEXT 0
#define BYTE 1
#define WORD 2
#define TIME 3
#define LONG 4
#define DUMP 5
#define SEU 6
#define COMP 7
unsigned char flags; /* various attributes: */
#define SUPPR 0x01 /* suppress it when -s? */
#define MAND 0x02 /* mandatory item */
#define PROMPT 0x04 /* prompt for user input */
#define SPACE 0x08 /* init to spaces */
unsigned char len; /* default/max length for pfhadd */
char *title;
};
/* table of known pfh items and their types and names */
struct pfh pfh[] =
{
0x01, LONG, 0x02, 4, "File-number",
0x02, TEXT, 0x0b, 8, "File-name",
0x03, TEXT, 0x0b, 3, "File-ext",
0x04, LONG, 0x02, 4, "File-size",
0x05, TIME, 0x02, 4, "Create-time",
0x06, TIME, 0x03, 4, "Last-modified-time",
0x07, SEU, 0x02, 1, "SEU-flag",
0x08, BYTE, 0x06, 1, "File-type",
0x09, WORD, 0x03, 2, "Body-checksum",
0x0a, WORD, 0x03, 2, "Header-checksum",
0x0b, WORD, 0x03, 2, "Body-offset",
0x10, TEXT, 0x06, 0, "Source",
0x11, TEXT, 0x0a, 6, "AX25-Uploader",
0x12, TIME, 0x02, 4, "Upload-time",
0x13, BYTE, 0x02, 1, "Download-count",
0x14, TEXT, 0x06, 0, "Destination",
0x15, TEXT, 0x0b, 6, "AX25-Downloader",
0x16, TIME, 0x02, 4, "Download-time",
0x17, TIME, 0x02, 4, "Expire-time",
0x18, BYTE, 0x07, 1, "Priority",
0x19, COMP, 0x04, 1, "Compression-type",
0x20, TEXT, 0x04, 1, "BBS-Message-type",
0x21, TEXT, 0x04, 0, "Bulletin-ID",
0x22, TEXT, 0x04, 0, "Title",
0x23, TEXT, 0x04, 0, "Keywords",
0x24, TEXT, 0x00, 0, "File-Description",
0x25, TEXT, 0x00, 0, "Compression-Description",
0x26, TEXT, 0x00, 0, "User-Filename",
0, DUMP, 0x00, 0, "Unknown-Header-type"
};
char nopfh[] = "%s: no Pacsat File Header\n";
char headcsum[] = "Warning: %s: header checksum error (%04x)\n";
char bodycsum[] = "Warning: %s: body checksum error (%04x)\n";
char writeerr[] = "Warning: write error in %s (disk full?)\n";
char linehead[] = " File_ID Ty Length To From Date/Time Title\n";
char hightext[] = "Hightime: %lx = %02d%02d%02d%02d%02d%02d (%.24s)\n";
char nomem[] = "Out of memory!\n";
unsigned char data[2048]; /* buffer */
char source[256];
char dest[256];
char title[256];
time_t hightime = 0; /* ul_time of newest file */
#if defined(__TURBOC__) || defined(MSDOS)
int pfhprint(char *,char *,int,int,int);
int pfhdir(char *);
int pfhtoc(int,char **);
int pfhline(char *,FILE *);
int cleandir(char *);
int pfhadd(char *,char *);
#else
int pfhprint(),pfhdir(),pfhtoc(),pfhline(),cleandir(),pfhadd();
#endif
/* main program. parse options, check argcount and call proper function */
int main (argc,argv)
int argc;
char *argv[];
{
int opermode = 0; /* operation mode (pfh/dir/toc) */
int suppress = 0; /* suppress some pfh items */
int headonly = 0; /* show only header, not file */
int strip7 = 0; /* bit-7 strip on body */
char *p;
/* get options */
while (argc > 1 && (argv[1][0] == '-' || argv[1][0] == '/'))
{
for (p = argv[1] + 1; *p; p++)
switch (*p)
{
case 'd':
case 'D':
opermode = 1; /* dirfile printout (short form) */
break;
case 't':
case 'T':
opermode = 2; /* toc of series of files (short form) */
break;
case 'c':
case 'C':
opermode = 3; /* cleanup a dirfile.dl file */
break;
case 'a':
case 'A':
opermode = 4; /* add PFH to file */
break;
case 's':
case 'S':
suppress = 1; /* omit boring headers */
break;
case 'h':
case 'H':
headonly = 1; /* don't output body */
break;
case '7':
strip7 = 1; /* strip bit 7 off Jeff's WS files */
break;
default:
argc = 0; /* force usage message */
break;
}
argv++;
argc--;
}
switch (opermode)
{
case 0:
if (argc == 2 || argc == 3)
return pfhprint(argv[1],argv[2],suppress,headonly,strip7);
break;
case 1:
if (argc == 2)
return pfhdir(argv[1]);
break;
case 2:
if (argc >= 2)
return pfhtoc(argc,argv);
break;
case 3:
if (argc == 2)
return cleandir(argv[1]);
break;
case 4:
if (argc == 3)
return pfhadd(argv[1],argv[2]);
break;
}
/* print usage message in case of arg error */
fprintf(stderr,"Usage: pfh [-s] [-h] [-7] <inputfile> [<outputfile>]\n");
fprintf(stderr," interprets Pacsat File Header on file\n");
fprintf(stderr," when <outputfile> specified, body is copied to it\n");
fprintf(stderr," -s option suppresses certain header items\n");
fprintf(stderr," -h option prints only the header, not the body\n");
fprintf(stderr," -7 option strips high bit when copying the body\n\n");
fprintf(stderr,"or: pfh -t <inputfile>...\n");
fprintf(stderr," prints PFH items in <inputfile>s in short format\n\n");
fprintf(stderr,"or: pfh -d <dirfile>\n");
fprintf(stderr," prints PFH items in <dirfile> in short format\n\n");
fprintf(stderr,"or: pfh -c <dirfile>\n");
fprintf(stderr," cleans <dirfile> (removes duplicate entries & sorts)\n\n");
fprintf(stderr,"or: pfh -a <inputfile> <outputfile>\n");
fprintf(stderr," adds PFH to file (prompts for header values)\n\n");
fprintf(stderr,"PFH utility program (c) 1991 by Rob Janssen, PE1CHL\n");
return 1;
}
/* printout PFH for specified inputfile, and copy body to specified */
/* outputfile, to stdout, or omit entirely */
pfhprint (inputfile,outputfile,suppress,headonly,strip7)
char *inputfile; /* inputfile name */
char *outputfile; /* outputfile, or NULL for stdout */
int suppress; /* header suppress flag */
int headonly; /* body omission flag */
int strip7; /* strip-high-bit flag */
{
FILE *inp,*out;
int id,id2,len,i;
unsigned long val;
unsigned int hsum,bsum,csum;
/* open inputfile */
if ((inp = fopen(inputfile,"rb")) == NULL)
{
perror(inputfile);
return 2;
}
/* check magic number AA55 */
if (fgetc(inp) != 0xaa || fgetc(inp) != 0x55)
{
fprintf(stderr,nopfh,inputfile);
fclose(inp);
return 3;
}
csum = 0xaa + 0x55;
/* read header items */
while ((id = fgetc(inp)) != EOF &&
(id2 = fgetc(inp)) != EOF &&
(len = fgetc(inp)) != EOF)
{
csum += id + id2 + len; /* update header checksum */
id |= id2 << 8;
if (id == 0 && len == 0) /* end of header? */
break;
if (fread(data,1,len,inp) != len) /* read data */
break;
data[len] = '\0';
if (len <= 4)
{
val = 0;
for (i = 0; i < len; i++)
val |= (unsigned long) data[i] << (8 * i);
}
/* special treatment for some header items */
switch (id)
{
case 0x0a: /* header checksum */
hsum = (unsigned)val; /* get it's value */
break; /* and don't update csum */
case 0x09: /* body checksum */
bsum = (unsigned)val; /* get value & update csum */
default:
for (i = 0; i < len; i++)
csum += data[i]; /* update header checksum */
break;
}
for (i = 0; pfh[i].id != 0; i++)
if (pfh[i].id == id)
break;
if (suppress && (pfh[i].flags & SUPPR))
continue;
printf("%s: ",pfh[i].title);
switch (pfh[i].type)
{
case TEXT:
if (data[0] == ' ' || data[strlen((char *) data) - 1] == ' ')
printf("\"%s\"\n",data);
else
printf("%s\n",data);
break;
case TIME:
if (len != 4)
goto badlen;
if (val == 0)
printf("not initialized\n");
else
printf("%.24s\n",ctime((time_t *) &val));
break;
case SEU:
if (len != 1)
goto badlen;
switch (data[0])
{
case 0:
printf("no Single Event Upsets\n");
break;
case 2:
printf("un");
case 1:
printf("correctable Single Event Upsets occurred\n");
break;
default:
printf("%u\n",data[0]);
}
break;
case COMP:
if (len != 1)
goto badlen;
switch (data[0])
{
case 0:
printf("not compressed\n");
break;
case 1:
printf("compressed using PKARC\n");
break;
case 2:
printf("compressed using PKZIP\n");
break;
case 255:
printf("see Compression-Description\n");
break;
default:
printf("0x%02x\n",data[0]);
break;
}
break;
case BYTE:
case WORD:
case LONG:
if (len == pfh[i].type)
{
printf("0x%0*lx %lu\n",len * 2,val,val);
break;
}
badlen:
default:
printf("id=0x%02x len=%d val=0x",id,len);
for (i = 0; i < len; i++)
printf("%02x",data[i]);
printf("\n");
break;
}
}
fflush(stdout);
if (hsum != csum)
fprintf(stderr,headcsum,inputfile,csum);
csum = 0;
/* test for outputfile requirement */
if (!headonly && outputfile != NULL)
{
/* create outputfile */
if ((out = fopen(outputfile,"wb")) == NULL)
{
perror(outputfile);
fclose(inp);
return 4;
}
/* copy rest of inputfile to ouputfile */
while ((len = (int)fread(data,1,sizeof(data),inp)) != 0) /* read data */
{
for (i = 0; i < len; i++)
{
csum += data[i]; /* calc checksum */
if (strip7)
data[i] &= 0x7f; /* clear high bit */
}
if (fwrite(data,1,len,out) != len) /* write to output */
{
perror(outputfile);
break;
}
}
if (ferror(out) || fclose(out) == EOF)
fprintf(stderr,writeerr,outputfile);
}
else
{
/* body to stdout, blank line between headers and body */
if (!headonly)
printf("\n");
/* read body and translate \r\n to \n on output */
while ((i = fgetc(inp)) != EOF)
{
csum += i;
if (headonly)
continue;
if (strip7)
i &= 0x7f;
if (i == '\r')
{
i = fgetc(inp);
csum += i;
if (strip7)
i &= 0x7f;
if (i == '\n')
printf("\n");
else
printf("\r%c",i);
}
else
printf("%c",i);
}
}
fflush(stdout);
if (bsum != csum)
fprintf(stderr,bodycsum,inputfile,csum);
fclose(inp);
return 0;
}
/* printout a downloaded directory (SELECT + DIR commands) */
pfhdir (inputfile)
char *inputfile;
{
FILE *inp;
struct tm *tm;
/* open inputfile */
if ((inp = fopen(inputfile,"rb")) == NULL)
{
perror(inputfile);
return 2;
}
printf(linehead);
while (pfhline(inputfile,inp) == 0)
;
if (!feof(inp))
{
fprintf(stderr,nopfh,inputfile);
fclose(inp);
return 3;
}
else
{
if (hightime)
{
tm = localtime(&hightime);
printf(hightext,hightime,
tm->tm_year,tm->tm_mon + 1,tm->tm_mday,
tm->tm_hour,tm->tm_min,tm->tm_sec,
ctime(&hightime));
}
}
fclose(inp);
return 0;
}
/* print table of contents for a series of downloaded files */
pfhtoc (argc,argv)
int argc;
char *argv[];
{
int n,r = 0;
char *inputfile;
FILE *inp;
printf(linehead);
for (n = 1; n < argc; n++)
{
/* open next inputfile */
if ((inp = fopen(inputfile = argv[n],"rb")) == NULL)
{
perror(inputfile);
r++;
}
else
{
/* display a single line of info from PFH */
if (pfhline(inputfile,inp))
{
fprintf(stderr,nopfh,inputfile);
r++;
}
fclose(inp);
}
}
return r;
}
/* display a single line of info from PFH, like a BBS "l" command */
int pfhline (filename,inp)
char *filename;
FILE *inp;
{
int id,id2,len,i;
unsigned long val;
unsigned int hsum,csum;
unsigned long file_id,length;
unsigned char file_type;
time_t file_time;
struct tm *tm;
/* check magic number AA55 */
if (fgetc(inp) != 0xaa || fgetc(inp) != 0x55)
return -1;
csum = 0xaa + 0x55;
/* set defaults */
file_id = length = 0;
file_type = 0;
file_time = 0;
source[0] = dest[0] = title[0] = '\0';
/* read header items */
while ((id = fgetc(inp)) != EOF &&
(id2 = fgetc(inp)) != EOF &&
(len = fgetc(inp)) != EOF)
{
csum += id + id2 + len; /* update header checksum */
id |= id2 << 8;
if (id == 0 && len == 0) /* end of header? */
break;
if (fread(data,1,len,inp) != len) /* read data */
break;
data[len] = '\0';
if (len <= 4)
{
val = 0;
for (i = 0; i < len; i++)
val |= (unsigned long) data[i] << (8 * i);
}
/* special treatment for some header items */
switch (id)
{
case 0x0a: /* header checksum */
hsum = (unsigned)val; /* get it's value */
break; /* and don't update csum */
default:
for (i = 0; i < len; i++)
csum += data[i]; /* update header checksum */
break;
}
/* interpret the interesting header items */
switch (id)
{
case 0x01: /* file_number */
file_id = val;
break;
case 0x02: /* file_name */
strcpy(title,(char *)data);
break;
case 0x04: /* file_size */
length = val;
break;
case 0x05: /* create_time */
file_time = val;
break;
case 0x08: /* file_type */
file_type = val;
break;
case 0x10: /* source */
strcpy(source,(char *)data);
break;
case 0x11: /* AX.25 uploader */
if (source[0] == '\0')
strcpy(source,(char *)data);
break;
case 0x12: /* upload_time */
file_time = val;
if ((long)val > hightime) /* keep highwater mark */
hightime = (long)val;
break;
case 0x14: /* destination */
strcpy(dest,(char *)data);
break;
case 0x22: /* title */
strcpy(title,(char *)data);
break;
case 0x26: /* user filename */
if (title[0] == '\0')
strcpy(title,(char *)data);
break;
}
}
if (hsum != csum)
fprintf(stderr,headcsum,filename,csum);
else {
printf("%08lx %02x%7lu %-12.12s%-10.10s",
file_id,file_type,length,dest,source);
if (file_time)
{
tm = localtime(&file_time);
printf("%02u%02u/%02u%02u",
tm->tm_mon + 1,tm->tm_mday,tm->tm_hour,tm->tm_min);
}
else
printf("????/????");
printf(" %s\n",title);
}
return 0;
}
/* clean a directory file. removes any duplicate entries and sorts it */
/* in upload_time order */
int cleandir (filename)
char *filename;
{
FILE *dir;
unsigned char *p;
int id,id2,len,i;
unsigned long val;
unsigned int hsum,csum;
unsigned long file_id;
time_t ul_time;
struct dir_entry
{
struct dir_entry *next,*prev;
unsigned long file_id;
time_t ul_time;
unsigned int length;
unsigned char entry[1];
} *entry_list,*new,*find;
/* open the existing dir file */
if ((dir = fopen(filename,"rb")) == NULL)
{
perror(filename);
return 2;
}
/* put dummy item in the list */
if ((entry_list = (struct dir_entry *) malloc(sizeof(struct dir_entry))) == NULL)
{
fprintf(stderr,nomem);
fclose(dir);
return 5;
}
entry_list->next = entry_list->prev = NULL;
entry_list->file_id = 0xffffffffL;
entry_list->ul_time = 0x7fffffffL;
entry_list->length = 0;
/* read all items from directory */
for (;;)
{
p = data;
file_id = 0;
ul_time = 0;
/* check magic number AA55 */
if ((*p++ = fgetc(dir)) != 0xaa || (*p++ = fgetc(dir)) != 0x55)
{
if (feof(dir))
break;
fprintf(stderr,nopfh,filename);
fclose(dir);
return 3;
}
csum = 0xaa + 0x55;
/* read header items */
while ((id = fgetc(dir)) != EOF &&
(id2 = fgetc(dir)) != EOF &&
(len = fgetc(dir)) != EOF)
{
*p++ = id;
*p++ = id2;
*p++ = len;
csum += id + id2 + len; /* update header checksum */
id |= id2 << 8;
if (id == 0 && len == 0) /* end of header? */
break;
if (fread(p,1,len,dir) != len) /* read data */
break;
if (len <= 4)
{
val = 0;
for (i = 0; i < len; i++)
val |= (unsigned long) p[i] << (8 * i);
}
/* special treatment for some header items */
switch (id)
{
case 0x0a: /* header checksum */
hsum = (unsigned)val; /* get it's value */
break; /* and don't update csum */
case 0x12: /* upload_time */
ul_time = val; /* get it */
goto addcsum; /* add to csum */
case 0x01: /* file_number */
file_id = val; /* get it & add to csum */
default:
addcsum:
for (i = 0; i < len; i++)
csum += p[i]; /* update header checksum */
break;
}
p += len;
}
if (hsum != csum)
{
fprintf(stderr,headcsum,filename,csum);
return 3;
}
if (file_id == 0)
continue;
/* save this file header in a list item */
if ((new = (struct dir_entry *) malloc(sizeof(struct dir_entry) + (unsigned)(p - data))) == NULL)
{
fprintf(stderr,nomem);
fclose(dir);
return 5;
}
new->next = new->prev = NULL;
new->file_id = file_id;
new->ul_time = ul_time;
new->length = (unsigned)(p - data);
memcpy(new->entry,data,new->length);
/* scan the list to find any duplicate entry for this file_id */
for (find = entry_list; find != NULL; find = find->next)
if (find->file_id == file_id)
{
/* it's a duplicate, delete it to keep latest copy */
if (find->prev != NULL)
find->prev->next = find->next;
else
entry_list = find->next;
if (find->next != NULL)
find->next->prev = find->prev;
free(find);
break;
}
/* scan the list to find it's place (insertion sort) */
for (find = entry_list; find != NULL; find = find->next)
if (find->ul_time > ul_time)
{
/* has to be inserted before this one */
if ((new->prev = find->prev) != NULL)
find->prev->next = new;
else
entry_list = new;
new->next = find;
find->prev = new;
break;
}
}
fclose(dir);
/* write the new dir file */
if ((dir = fopen(filename,"wb")) == NULL)
{
perror(filename);
return 4;
}
while (entry_list != NULL)
{
if (fwrite(entry_list->entry,1,entry_list->length,dir) != entry_list->length)
{
perror(filename);
fclose(dir);
unlink(filename);
return 6;
}
entry_list = entry_list->next;
}
fclose(dir);
return 0;
}
/* add a PFH to a file, for upload to the server */
int pfhadd (inputfile,outputfile)
char *inputfile; /* inputfile name */
char *outputfile; /* outputfile name */
{
FILE *inp,*out;
struct pfh *pi;
int len;
unsigned int csum;
unsigned long val;
unsigned long fsizepos,bcsumpos,hcsumpos,boffpos,bodypos;
unsigned char ftype = 0,ctype = 0;
time_t now;
/* open inputfile */
if ((inp = fopen(inputfile,"rb")) == NULL)
{
perror(inputfile);
return 2;
}
/* create outputfile */
if ((out = fopen(outputfile,"w+b")) == NULL)
{
perror(outputfile);
fclose(inp);
return 4;
}
time(&now); /* get default time */
fputc(0xaa,out); /* PFH magic number */
fputc(0x55,out);
for (pi = pfh; pi->id != 0; pi++)
{
if (pi->flags & PROMPT || /* user-input item? */
(pi->id == 0x24 && ftype == 255) || /* file description? */
(pi->id == 0x25 && ctype == 255)) /* compression description? */
{
printf("%s: ",pi->title); /* disp the prompt */
if (gets((char *)data) == NULL)
data[0] = '\0';
len = 0; /* no conversion = no data */
switch (pi->type) /* conversion depending on type */
{
case TEXT:
len = (int)strlen((char *)data); /* use user-supplied data len */
if (pi->len != 0 && len > pi->len)
len = pi->len;
break;
case BYTE:
case WORD:
case LONG:
val = atol((char *)data); /* get value of decimal input */
data[0] = (unsigned char)val; /* convert to little-endian */
data[1] = (unsigned char)(val >> 8);
data[2] = (unsigned char)(val >> 16);
data[3] = (unsigned char)(val >> 24);
len = pi->type;
break;
case COMP:
if (strstr((char *)data,"arc") != NULL)
data[0] = 1;
else
if (strstr((char *)data,"zip") != NULL)
data[0] = 2;
else
data[0] = (unsigned char)atoi((char *)data);
len = 1;
}
}
else /* else must be fixed item */
{
memset(data,(pi->flags & SPACE? ' ':'\0'),len = pi->len);
}
switch (pi->id) /* special treatment for some items */
{
case 0x04: /* file_size */
fsizepos = ftell(out) + 3;
break;
case 0x05: /* create_time */
data[0] = (unsigned char)now; /* convert time to little-endian */
data[1] = (unsigned char)(now >> 8);
data[2] = (unsigned char)(now >> 16);
data[3] = (unsigned char)(now >> 24);
break;
case 0x08: /* file_type */
ftype = data[0];
break;
case 0x09: /* body_checksum */
bcsumpos = ftell(out) + 3;
break;
case 0x0a: /* header_checksum */
hcsumpos = ftell(out) + 3;
break;
case 0x0b: /* body_offset */
boffpos = ftell(out) + 3;
break;
case 0x19: /* compression_type */
ctype = data[0];
break;
case 0x26: /* user_filename */
strcpy((char *)data,inputfile);
len = (int)strlen((char *)data);
break;
}
if (len != 0 || (pi->flags & MAND))
{
fputc((unsigned char)pi->id,out); /* write the item */
fputc((unsigned char)(pi->id >> 8),out);
fputc((unsigned char)len,out);
fwrite(data,1,len,out);
}
}
fputc(0,out); /* terminate PFH */
fputc(0,out);
fputc(0,out);
/* get body offset */
bodypos = ftell(out);
/* copy file to output, taking checksum */
csum = 0;
while ((len = (int)fread(data,1,sizeof(data),inp)) != 0) /* read data */
{
fwrite(data,1,len,out); /* write to output */
while (len > 0) /* update checksum */
csum += data[--len];
}
/* store total file size */
val = ftell(out);
fseek(out,fsizepos,0);
fputc((unsigned char)val,out);
fputc((unsigned char)(val >> 8),out);
fputc((unsigned char)(val >> 16),out);
fputc((unsigned char)(val >> 24),out);
/* store calculated body checksum */
fseek(out,bcsumpos,0);
fputc((unsigned char)csum,out);
fputc((unsigned char)(csum >> 8),out);
/* set correct body offset */
fseek(out,boffpos,0);
fputc((unsigned char)bodypos,out);
fputc((unsigned char)(bodypos >> 8),out);
/* calculate header checksum */
csum = 0;
fseek(out,0L,0);
while (bodypos-- > 0)
csum += fgetc(out);
/* store calculated header checksum */
fseek(out,hcsumpos,0);
fputc((unsigned char)csum,out);
fputc((unsigned char)(csum >> 8),out);
if (ferror(out))
fprintf(stderr,writeerr,outputfile);
fclose(inp);
fclose(out);
return 0;
}